
#include "Agent.h"
#include "Random.h"
#include "Environment.h"
#include <string.h>
#include <unistd.h>
#include <iostream>

using namespace std;

Agent::Agent(const char* name, Synch* s, int row, int col) {
    strncpy(m_myName, name, THREAD_NAME_LENGTH);
    m_mySynch = s;
    m_Row = row;
    m_Column = col;
    EnvCell* tmpCell = Environment::getCell(m_Row, m_Column);
    //pthread_mutex_lock(&cellLocker);
    tmpCell->agentArrived();
    //pthread_mutex_unlock(&cellLocker);
}

void Agent::moveAgent() {
    int randomNum = Random::getRandomNum(100);
    int maxRow = BOARD_ROWS;
    int maxCol = BOARD_COLUMNS;
    EnvCell* tmpCell = Environment::getCell(m_Row, m_Column);
    tmpCell->agentDeparted();
    if (randomNum <= 25) { // move up
        if (m_Row != 0) {
            m_Row--;
        } else {
            m_Row++;
        }
    } else if (randomNum <= 50) { //move down
        if (m_Row != (maxRow - 1)) {//    (BOARD_ROWS - 1)   <- doesn't work...
            m_Row++;
        } else {
            m_Row--;
        }
    } else if (randomNum <= 75) { //move left
        if (m_Column != 0) {
            m_Column--;
        } else {
            m_Column++;
        }
    } else {
        if (m_Column != (maxCol - 1)) {//   (BOARD_COLUMNS-1)<- doesn't work...
            m_Column++;
        } else {
            m_Column--;
        }
    }
    tmpCell = Environment::getCell(m_Row, m_Column);
    tmpCell->agentArrived();

}

void Agent::run() {
    EnvCell* tmpCell;

    m_mySynch->startAgent(this);

    while (true) {
        if (m_mySynch->sleep()) {
            usleep(300000);
        }
        Lock();
        if (m_mySynch->pause()) {
            while (m_mySynch->pause()) {
                //Place particle if one is held
                if (m_pickedParticle != NULL) {
                    tmpCell = Environment::getCell(m_Row, m_Column);
                    tmpCell->placeParticle(m_pickedParticle);
                    //tmpCell->agentDeparted();
                    m_pickedParticle = NULL;
                }
                this->wait();
            }
        }
        Unlock();

        //check if it should terminate
        if (m_mySynch->terminate()) {
            tmpCell = Environment::getCell(m_Row, m_Column);
            tmpCell->agentDeparted();
            if (m_pickedParticle != NULL) {
                tmpCell->placeParticle(m_pickedParticle);                
                m_pickedParticle = NULL;
            }
            pthread_exit(this);
        }

        //Probabilistically place a particle
        if (m_pickedParticle != NULL) {

            if (Random::getRandomNum(100) <= CHANCE_PLACE_PARTICLE) {//place particle
                tmpCell = Environment::getCell(m_Row, m_Column);
                tmpCell->placeParticle(m_pickedParticle);
                m_pickedParticle = NULL;
            }

        }

        //Move agent
        pthread_mutex_lock(&moveLocker);
        moveAgent();
        pthread_mutex_unlock(&moveLocker);

        //Probabilistically pick up
        if (m_pickedParticle == NULL) {

            if (Random::getRandomNum(100) <= CHANCE_TAKE_PARTICLE) {//place particle
                //pthread_mutex_lock(&cellLocker);
                tmpCell = Environment::getCell(m_Row, m_Column);
                m_pickedParticle = tmpCell->takeParticle();
                //pthread_mutex_unlock(&cellLocker);
                
            }

        }

    }//end while
}//run()

pthread_mutex_t Agent::moveLocker;
pthread_mutex_t Agent::cellLocker;